/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
var mxPerimeter =
    {
        /**
         * Class: mxPerimeter
         *
         * Provides various perimeter functions to be used in a style
         * as the value of <mxConstants.STYLE_PERIMETER>. Perimeters for
         * rectangle, circle, rhombus and triangle are available.
         *
         * Example:
         *
         * (code)
         * <add as="perimeter">mxPerimeter.RectanglePerimeter</add>
         * (end)
         *
         * Or programmatically:
         *
         * (code)
         * style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter;
         * (end)
         *
         * When adding new perimeter functions, it is recommended to use the
         * mxPerimeter-namespace as follows:
         *
         * (code)
         * mxPerimeter.CustomPerimeter = function (bounds, vertex, next, orthogonal)
         * {
         *   var x = 0; // Calculate x-coordinate
         *   var y = 0; // Calculate y-coordainte
         *
         *   return new mxPoint(x, y);
         * }
         * (end)
         *
         * The new perimeter should then be registered in the <mxStyleRegistry> as follows:
         * (code)
         * mxStyleRegistry.putValue('customPerimeter', mxPerimeter.CustomPerimeter);
         * (end)
         *
         * The custom perimeter above can now be used in a specific vertex as follows:
         *
         * (code)
         * model.setStyle(vertex, 'perimeter=customPerimeter');
         * (end)
         *
         * Note that the key of the <mxStyleRegistry> entry for the function should
         * be used in string values, unless <mxGraphView.allowEval> is true, in
         * which case you can also use mxPerimeter.CustomPerimeter for the value in
         * the cell style above.
         *
         * Or it can be used for all vertices in the graph as follows:
         *
         * (code)
         * var style = graph.getStylesheet().getDefaultVertexStyle();
         * style[mxConstants.STYLE_PERIMETER] = mxPerimeter.CustomPerimeter;
         * (end)
         *
         * Note that the object can be used directly when programmatically setting
         * the value, but the key in the <mxStyleRegistry> should be used when
         * setting the value via a key, value pair in a cell style.
         *
         * The parameters are explained in <RectanglePerimeter>.
         *
         * Function: RectanglePerimeter
         *
         * Describes a rectangular perimeter for the given bounds.
         *
         * Parameters:
         *
         * bounds - <mxRectangle> that represents the absolute bounds of the
         * vertex.
         * vertex - <mxCellState> that represents the vertex.
         * next - <mxPoint> that represents the nearest neighbour point on the
         * given edge.
         * orthogonal - Boolean that specifies if the orthogonal projection onto
         * the perimeter should be returned. If this is false then the intersection
         * of the perimeter and the line between the next and the center point is
         * returned.
         */
        RectanglePerimeter: function (bounds, vertex, next, orthogonal)
        {
            var cx = bounds.getCenterX();
            var cy = bounds.getCenterY();
            var dx = next.x - cx;
            var dy = next.y - cy;
            var alpha = Math.atan2(dy, dx);
            var p = new mxPoint(0, 0);
            var pi = Math.PI;
            var pi2 = Math.PI/2;
            var beta = pi2 - alpha;
            var t = Math.atan2(bounds.height, bounds.width);

            if (alpha < -pi + t || alpha > pi - t)
            {
                // Left edge
                p.x = bounds.x;
                p.y = cy - bounds.width * Math.tan(alpha) / 2;
            }
            else if (alpha < -t)
            {
                // Top Edge
                p.y = bounds.y;
                p.x = cx - bounds.height * Math.tan(beta) / 2;
            }
            else if (alpha < t)
            {
                // Right Edge
                p.x = bounds.x + bounds.width;
                p.y = cy + bounds.width * Math.tan(alpha) / 2;
            }
            else
            {
                // Bottom Edge
                p.y = bounds.y + bounds.height;
                p.x = cx + bounds.height * Math.tan(beta) / 2;
            }

            if (orthogonal)
            {
                if (next.x >= bounds.x &&
                    next.x <= bounds.x + bounds.width)
                {
                    p.x = next.x;
                }
                else if (next.y >= bounds.y &&
                    next.y <= bounds.y + bounds.height)
                {
                    p.y = next.y;
                }
                if (next.x < bounds.x)
                {
                    p.x = bounds.x;
                }
                else if (next.x > bounds.x + bounds.width)
                {
                    p.x = bounds.x + bounds.width;
                }
                if (next.y < bounds.y)
                {
                    p.y = bounds.y;
                }
                else if (next.y > bounds.y + bounds.height)
                {
                    p.y = bounds.y + bounds.height;
                }
            }

            return p;
        },

        /**
         * Function: EllipsePerimeter
         *
         * Describes an elliptic perimeter. See <RectanglePerimeter>
         * for a description of the parameters.
         */
        EllipsePerimeter: function (bounds, vertex, next, orthogonal)
        {
            var x = bounds.x;
            var y = bounds.y;
            var a = bounds.width / 2;
            var b = bounds.height / 2;
            var cx = x + a;
            var cy = y + b;
            var px = next.x;
            var py = next.y;

            // Calculates straight line equation through
            // point and ellipse center y = d * x + h
            var dx = parseInt(px - cx);
            var dy = parseInt(py - cy);

            if (dx == 0 && dy != 0)
            {
                return new mxPoint(cx, cy + b * dy / Math.abs(dy));
            }
            else if (dx == 0 && dy == 0)
            {
                return new mxPoint(px, py);
            }

            if (orthogonal)
            {
                if (py >= y && py <= y + bounds.height)
                {
                    var ty = py - cy;
                    var tx = Math.sqrt(a*a*(1-(ty*ty)/(b*b))) || 0;

                    if (px <= x)
                    {
                        tx = -tx;
                    }

                    return new mxPoint(cx+tx, py);
                }

                if (px >= x && px <= x + bounds.width)
                {
                    var tx = px - cx;
                    var ty = Math.sqrt(b*b*(1-(tx*tx)/(a*a))) || 0;

                    if (py <= y)
                    {
                        ty = -ty;
                    }

                    return new mxPoint(px, cy+ty);
                }
            }

            // Calculates intersection
            var d = dy / dx;
            var h = cy - d * cx;
            var e = a * a * d * d + b * b;
            var f = -2 * cx * e;
            var g = a * a * d * d * cx * cx +
                b * b * cx * cx -
                a * a * b * b;
            var det = Math.sqrt(f * f - 4 * e * g);

            // Two solutions (perimeter points)
            var xout1 = (-f + det) / (2 * e);
            var xout2 = (-f - det) / (2 * e);
            var yout1 = d * xout1 + h;
            var yout2 = d * xout2 + h;
            var dist1 = Math.sqrt(Math.pow((xout1 - px), 2)
                + Math.pow((yout1 - py), 2));
            var dist2 = Math.sqrt(Math.pow((xout2 - px), 2)
                + Math.pow((yout2 - py), 2));

            // Correct solution
            var xout = 0;
            var yout = 0;

            if (dist1 < dist2)
            {
                xout = xout1;
                yout = yout1;
            }
            else
            {
                xout = xout2;
                yout = yout2;
            }

            return new mxPoint(xout, yout);
        },

        /**
         * Function: RhombusPerimeter
         *
         * Describes a rhombus (aka diamond) perimeter. See <RectanglePerimeter>
         * for a description of the parameters.
         */
        RhombusPerimeter: function (bounds, vertex, next, orthogonal)
        {
            var x = bounds.x;
            var y = bounds.y;
            var w = bounds.width;
            var h = bounds.height;

            var cx = x + w / 2;
            var cy = y + h / 2;

            var px = next.x;
            var py = next.y;

            // Special case for intersecting the diamond's corners
            if (cx == px)
            {
                if (cy > py)
                {
                    return new mxPoint(cx, y); // top
                }
                else
                {
                    return new mxPoint(cx, y + h); // bottom
                }
            }
            else if (cy == py)
            {
                if (cx > px)
                {
                    return new mxPoint(x, cy); // left
                }
                else
                {
                    return new mxPoint(x + w, cy); // right
                }
            }

            var tx = cx;
            var ty = cy;

            if (orthogonal)
            {
                if (px >= x && px <= x + w)
                {
                    tx = px;
                }
                else if (py >= y && py <= y + h)
                {
                    ty = py;
                }
            }

            // In which quadrant will the intersection be?
            // set the slope and offset of the border line accordingly
            if (px < cx)
            {
                if (py < cy)
                {
                    return mxUtils.intersection(px, py, tx, ty, cx, y, x, cy);
                }
                else
                {
                    return mxUtils.intersection(px, py, tx, ty, cx, y + h, x, cy);
                }
            }
            else if (py < cy)
            {
                return mxUtils.intersection(px, py, tx, ty, cx, y, x + w, cy);
            }
            else
            {
                return mxUtils.intersection(px, py, tx, ty, cx, y + h, x + w, cy);
            }
        },

        /**
         * Function: TrianglePerimeter
         *
         * Describes a triangle perimeter. See <RectanglePerimeter>
         * for a description of the parameters.
         */
        TrianglePerimeter: function (bounds, vertex, next, orthogonal)
        {
            var direction = (vertex != null) ?
                vertex.style[mxConstants.STYLE_DIRECTION] : null;
            var vertical = direction == mxConstants.DIRECTION_NORTH ||
                direction == mxConstants.DIRECTION_SOUTH;

            var x = bounds.x;
            var y = bounds.y;
            var w = bounds.width;
            var h = bounds.height;

            var cx = x + w / 2;
            var cy = y + h / 2;

            var start = new mxPoint(x, y);
            var corner = new mxPoint(x + w, cy);
            var end = new mxPoint(x, y + h);

            if (direction == mxConstants.DIRECTION_NORTH)
            {
                start = end;
                corner = new mxPoint(cx, y);
                end = new mxPoint(x + w, y + h);
            }
            else if (direction == mxConstants.DIRECTION_SOUTH)
            {
                corner = new mxPoint(cx, y + h);
                end = new mxPoint(x + w, y);
            }
            else if (direction == mxConstants.DIRECTION_WEST)
            {
                start = new mxPoint(x + w, y);
                corner = new mxPoint(x, cy);
                end = new mxPoint(x + w, y + h);
            }

            var dx = next.x - cx;
            var dy = next.y - cy;

            var alpha = (vertical) ? Math.atan2(dx, dy) : Math.atan2(dy, dx);
            var t = (vertical) ? Math.atan2(w, h) : Math.atan2(h, w);

            var base = false;

            if (direction == mxConstants.DIRECTION_NORTH ||
                direction == mxConstants.DIRECTION_WEST)
            {
                base = alpha > -t && alpha < t;
            }
            else
            {
                base = alpha < -Math.PI + t || alpha > Math.PI - t;
            }

            var result = null;

            if (base)
            {
                if (orthogonal && ((vertical && next.x >= start.x && next.x <= end.x) ||
                    (!vertical && next.y >= start.y && next.y <= end.y)))
                {
                    if (vertical)
                    {
                        result = new mxPoint(next.x, start.y);
                    }
                    else
                    {
                        result = new mxPoint(start.x, next.y);
                    }
                }
                else
                {
                    if (direction == mxConstants.DIRECTION_NORTH)
                    {
                        result = new mxPoint(x + w / 2 + h * Math.tan(alpha) / 2,
                            y + h);
                    }
                    else if (direction == mxConstants.DIRECTION_SOUTH)
                    {
                        result = new mxPoint(x + w / 2 - h * Math.tan(alpha) / 2,
                            y);
                    }
                    else if (direction == mxConstants.DIRECTION_WEST)
                    {
                        result = new mxPoint(x + w, y + h / 2 +
                            w * Math.tan(alpha) / 2);
                    }
                    else
                    {
                        result = new mxPoint(x, y + h / 2 -
                            w * Math.tan(alpha) / 2);
                    }
                }
            }
            else
            {
                if (orthogonal)
                {
                    var pt = new mxPoint(cx, cy);

                    if (next.y >= y && next.y <= y + h)
                    {
                        pt.x = (vertical) ? cx : (
                            (direction == mxConstants.DIRECTION_WEST) ?
                                x + w : x);
                        pt.y = next.y;
                    }
                    else if (next.x >= x && next.x <= x + w)
                    {
                        pt.x = next.x;
                        pt.y = (!vertical) ? cy : (
                            (direction == mxConstants.DIRECTION_NORTH) ?
                                y + h : y);
                    }

                    // Compute angle
                    dx = next.x - pt.x;
                    dy = next.y - pt.y;

                    cx = pt.x;
                    cy = pt.y;
                }

                if ((vertical && next.x <= x + w / 2) ||
                    (!vertical && next.y <= y + h / 2))
                {
                    result = mxUtils.intersection(next.x, next.y, cx, cy,
                        start.x, start.y, corner.x, corner.y);
                }
                else
                {
                    result = mxUtils.intersection(next.x, next.y, cx, cy,
                        corner.x, corner.y, end.x, end.y);
                }
            }

            if (result == null)
            {
                result = new mxPoint(cx, cy);
            }

            return result;
        },

        /**
         * Function: HexagonPerimeter
         *
         * Describes a hexagon perimeter. See <RectanglePerimeter>
         * for a description of the parameters.
         */
        HexagonPerimeter: function (bounds, vertex, next, orthogonal)
        {
            var x = bounds.x;
            var y = bounds.y;
            var w = bounds.width;
            var h = bounds.height;

            var cx = bounds.getCenterX();
            var cy = bounds.getCenterY();
            var px = next.x;
            var py = next.y;
            var dx = px - cx;
            var dy = py - cy;
            var alpha = -Math.atan2(dy, dx);
            var pi = Math.PI;
            var pi2 = Math.PI / 2;

            var result = new mxPoint(cx, cy);

            var direction = (vertex != null) ? mxUtils.getValue(
                vertex.style, mxConstants.STYLE_DIRECTION,
                mxConstants.DIRECTION_EAST) : mxConstants.DIRECTION_EAST;
            var vertical = direction == mxConstants.DIRECTION_NORTH
                || direction == mxConstants.DIRECTION_SOUTH;
            var a = new mxPoint();
            var b = new mxPoint();

            //Only consider corrects quadrants for the orthogonal case.
            if ((px < x) && (py < y) || (px < x) && (py > y + h)
                || (px > x + w) && (py < y) || (px > x + w) && (py > y + h))
            {
                orthogonal = false;
            }

            if (orthogonal)
            {
                if (vertical)
                {
                    //Special cases where intersects with hexagon corners
                    if (px == cx)
                    {
                        if (py <= y)
                        {
                            return new mxPoint(cx, y);
                        }
                        else if (py >= y + h)
                        {
                            return new mxPoint(cx, y + h);
                        }
                    }
                    else if (px < x)
                    {
                        if (py == y + h / 4)
                        {
                            return new mxPoint(x, y + h / 4);
                        }
                        else if (py == y + 3 * h / 4)
                        {
                            return new mxPoint(x, y + 3 * h / 4);
                        }
                    }
                    else if (px > x + w)
                    {
                        if (py == y + h / 4)
                        {
                            return new mxPoint(x + w, y + h / 4);
                        }
                        else if (py == y + 3 * h / 4)
                        {
                            return new mxPoint(x + w, y + 3 * h / 4);
                        }
                    }
                    else if (px == x)
                    {
                        if (py < cy)
                        {
                            return new mxPoint(x, y + h / 4);
                        }
                        else if (py > cy)
                        {
                            return new mxPoint(x, y + 3 * h / 4);
                        }
                    }
                    else if (px == x + w)
                    {
                        if (py < cy)
                        {
                            return new mxPoint(x + w, y + h / 4);
                        }
                        else if (py > cy)
                        {
                            return new mxPoint(x + w, y + 3 * h / 4);
                        }
                    }
                    if (py == y)
                    {
                        return new mxPoint(cx, y);
                    }
                    else if (py == y + h)
                    {
                        return new mxPoint(cx, y + h);
                    }

                    if (px < cx)
                    {
                        if ((py > y + h / 4) && (py < y + 3 * h / 4))
                        {
                            a = new mxPoint(x, y);
                            b = new mxPoint(x, y + h);
                        }
                        else if (py < y + h / 4)
                        {
                            a = new mxPoint(x - Math.floor(0.5 * w), y
                                + Math.floor(0.5 * h));
                            b = new mxPoint(x + w, y - Math.floor(0.25 * h));
                        }
                        else if (py > y + 3 * h / 4)
                        {
                            a = new mxPoint(x - Math.floor(0.5 * w), y
                                + Math.floor(0.5 * h));
                            b = new mxPoint(x + w, y + Math.floor(1.25 * h));
                        }
                    }
                    else if (px > cx)
                    {
                        if ((py > y + h / 4) && (py < y + 3 * h / 4))
                        {
                            a = new mxPoint(x + w, y);
                            b = new mxPoint(x + w, y + h);
                        }
                        else if (py < y + h / 4)
                        {
                            a = new mxPoint(x, y - Math.floor(0.25 * h));
                            b = new mxPoint(x + Math.floor(1.5 * w), y
                                + Math.floor(0.5 * h));
                        }
                        else if (py > y + 3 * h / 4)
                        {
                            a = new mxPoint(x + Math.floor(1.5 * w), y
                                + Math.floor(0.5 * h));
                            b = new mxPoint(x, y + Math.floor(1.25 * h));
                        }
                    }

                }
                else
                {
                    //Special cases where intersects with hexagon corners
                    if (py == cy)
                    {
                        if (px <= x)
                        {
                            return new mxPoint(x, y + h / 2);
                        }
                        else if (px >= x + w)
                        {
                            return new mxPoint(x + w, y + h / 2);
                        }
                    }
                    else if (py < y)
                    {
                        if (px == x + w / 4)
                        {
                            return new mxPoint(x + w / 4, y);
                        }
                        else if (px == x + 3 * w / 4)
                        {
                            return new mxPoint(x + 3 * w / 4, y);
                        }
                    }
                    else if (py > y + h)
                    {
                        if (px == x + w / 4)
                        {
                            return new mxPoint(x + w / 4, y + h);
                        }
                        else if (px == x + 3 * w / 4)
                        {
                            return new mxPoint(x + 3 * w / 4, y + h);
                        }
                    }
                    else if (py == y)
                    {
                        if (px < cx)
                        {
                            return new mxPoint(x + w / 4, y);
                        }
                        else if (px > cx)
                        {
                            return new mxPoint(x + 3 * w / 4, y);
                        }
                    }
                    else if (py == y + h)
                    {
                        if (px < cx)
                        {
                            return new mxPoint(x + w / 4, y + h);
                        }
                        else if (py > cy)
                        {
                            return new mxPoint(x + 3 * w / 4, y + h);
                        }
                    }
                    if (px == x)
                    {
                        return new mxPoint(x, cy);
                    }
                    else if (px == x + w)
                    {
                        return new mxPoint(x + w, cy);
                    }

                    if (py < cy)
                    {
                        if ((px > x + w / 4) && (px < x + 3 * w / 4))
                        {
                            a = new mxPoint(x, y);
                            b = new mxPoint(x + w, y);
                        }
                        else if (px < x + w / 4)
                        {
                            a = new mxPoint(x - Math.floor(0.25 * w), y + h);
                            b = new mxPoint(x + Math.floor(0.5 * w), y
                                - Math.floor(0.5 * h));
                        }
                        else if (px > x + 3 * w / 4)
                        {
                            a = new mxPoint(x + Math.floor(0.5 * w), y
                                - Math.floor(0.5 * h));
                            b = new mxPoint(x + Math.floor(1.25 * w), y + h);
                        }
                    }
                    else if (py > cy)
                    {
                        if ((px > x + w / 4) && (px < x + 3 * w / 4))
                        {
                            a = new mxPoint(x, y + h);
                            b = new mxPoint(x + w, y + h);
                        }
                        else if (px < x + w / 4)
                        {
                            a = new mxPoint(x - Math.floor(0.25 * w), y);
                            b = new mxPoint(x + Math.floor(0.5 * w), y
                                + Math.floor(1.5 * h));
                        }
                        else if (px > x + 3 * w / 4)
                        {
                            a = new mxPoint(x + Math.floor(0.5 * w), y
                                + Math.floor(1.5 * h));
                            b = new mxPoint(x + Math.floor(1.25 * w), y);
                        }
                    }
                }

                var tx = cx;
                var ty = cy;

                if (px >= x && px <= x + w)
                {
                    tx = px;

                    if (py < cy)
                    {
                        ty = y + h;
                    }
                    else
                    {
                        ty = y;
                    }
                }
                else if (py >= y && py <= y + h)
                {
                    ty = py;

                    if (px < cx)
                    {
                        tx = x + w;
                    }
                    else
                    {
                        tx = x;
                    }
                }

                result = mxUtils.intersection(tx, ty, next.x, next.y, a.x, a.y, b.x, b.y);
            }
            else
            {
                if (vertical)
                {
                    var beta = Math.atan2(h / 4, w / 2);

                    //Special cases where intersects with hexagon corners
                    if (alpha == beta)
                    {
                        return new mxPoint(x + w, y + Math.floor(0.25 * h));
                    }
                    else if (alpha == pi2)
                    {
                        return new mxPoint(x + Math.floor(0.5 * w), y);
                    }
                    else if (alpha == (pi - beta))
                    {
                        return new mxPoint(x, y + Math.floor(0.25 * h));
                    }
                    else if (alpha == -beta)
                    {
                        return new mxPoint(x + w, y + Math.floor(0.75 * h));
                    }
                    else if (alpha == (-pi2))
                    {
                        return new mxPoint(x + Math.floor(0.5 * w), y + h);
                    }
                    else if (alpha == (-pi + beta))
                    {
                        return new mxPoint(x, y + Math.floor(0.75 * h));
                    }

                    if ((alpha < beta) && (alpha > -beta))
                    {
                        a = new mxPoint(x + w, y);
                        b = new mxPoint(x + w, y + h);
                    }
                    else if ((alpha > beta) && (alpha < pi2))
                    {
                        a = new mxPoint(x, y - Math.floor(0.25 * h));
                        b = new mxPoint(x + Math.floor(1.5 * w), y
                            + Math.floor(0.5 * h));
                    }
                    else if ((alpha > pi2) && (alpha < (pi - beta)))
                    {
                        a = new mxPoint(x - Math.floor(0.5 * w), y
                            + Math.floor(0.5 * h));
                        b = new mxPoint(x + w, y - Math.floor(0.25 * h));
                    }
                    else if (((alpha > (pi - beta)) && (alpha <= pi))
                        || ((alpha < (-pi + beta)) && (alpha >= -pi)))
                    {
                        a = new mxPoint(x, y);
                        b = new mxPoint(x, y + h);
                    }
                    else if ((alpha < -beta) && (alpha > -pi2))
                    {
                        a = new mxPoint(x + Math.floor(1.5 * w), y
                            + Math.floor(0.5 * h));
                        b = new mxPoint(x, y + Math.floor(1.25 * h));
                    }
                    else if ((alpha < -pi2) && (alpha > (-pi + beta)))
                    {
                        a = new mxPoint(x - Math.floor(0.5 * w), y
                            + Math.floor(0.5 * h));
                        b = new mxPoint(x + w, y + Math.floor(1.25 * h));
                    }
                }
                else
                {
                    var beta = Math.atan2(h / 2, w / 4);

                    //Special cases where intersects with hexagon corners
                    if (alpha == beta)
                    {
                        return new mxPoint(x + Math.floor(0.75 * w), y);
                    }
                    else if (alpha == (pi - beta))
                    {
                        return new mxPoint(x + Math.floor(0.25 * w), y);
                    }
                    else if ((alpha == pi) || (alpha == -pi))
                    {
                        return new mxPoint(x, y + Math.floor(0.5 * h));
                    }
                    else if (alpha == 0)
                    {
                        return new mxPoint(x + w, y + Math.floor(0.5 * h));
                    }
                    else if (alpha == -beta)
                    {
                        return new mxPoint(x + Math.floor(0.75 * w), y + h);
                    }
                    else if (alpha == (-pi + beta))
                    {
                        return new mxPoint(x + Math.floor(0.25 * w), y + h);
                    }

                    if ((alpha > 0) && (alpha < beta))
                    {
                        a = new mxPoint(x + Math.floor(0.5 * w), y
                            - Math.floor(0.5 * h));
                        b = new mxPoint(x + Math.floor(1.25 * w), y + h);
                    }
                    else if ((alpha > beta) && (alpha < (pi - beta)))
                    {
                        a = new mxPoint(x, y);
                        b = new mxPoint(x + w, y);
                    }
                    else if ((alpha > (pi - beta)) && (alpha < pi))
                    {
                        a = new mxPoint(x - Math.floor(0.25 * w), y + h);
                        b = new mxPoint(x + Math.floor(0.5 * w), y
                            - Math.floor(0.5 * h));
                    }
                    else if ((alpha < 0) && (alpha > -beta))
                    {
                        a = new mxPoint(x + Math.floor(0.5 * w), y
                            + Math.floor(1.5 * h));
                        b = new mxPoint(x + Math.floor(1.25 * w), y);
                    }
                    else if ((alpha < -beta) && (alpha > (-pi + beta)))
                    {
                        a = new mxPoint(x, y + h);
                        b = new mxPoint(x + w, y + h);
                    }
                    else if ((alpha < (-pi + beta)) && (alpha > -pi))
                    {
                        a = new mxPoint(x - Math.floor(0.25 * w), y);
                        b = new mxPoint(x + Math.floor(0.5 * w), y
                            + Math.floor(1.5 * h));
                    }
                }

                result = mxUtils.intersection(cx, cy, next.x, next.y, a.x, a.y, b.x, b.y);
            }

            if (result == null)
            {
                return new mxPoint(cx, cy);
            }

            return result;
        }
    };
